﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using ImageFan.Auxiliary;
using ImageFan.ImageHandling;

namespace ImageFan.Controls
{
    internal partial class ThumbnailsSequence
        : FlowLayoutPanel
    {
        public ThumbnailsSequence()
        {
            InitializeComponent();

            DoubleBuffered = true;
            VerticalScroll.SmallChange = 25;
            VerticalScroll.LargeChange = 50;

            _allowSetThumbnailBorder = true;
            _imageFiles = new List<ImageFile>();
        }

        public void SetPendingAction()
        {
            _pendingAction = true;
        }

        public void DisposeOfPreviousThumbnails()
        {
            Controls.Clear();
            _currentThumbnail = null;
            AutoScrollPosition = Point0;

            foreach (var anImageFile in _imageFiles)
                anImageFile.Dispose();
        }

        public void ShowThumbnails()
        {
            SuspendLayout();

            StopThumbnailsGeneration();
            GetImageFiles();

            ResumeLayout(true);

            SetThumbnails();
        }

        public string CurrentDirectory
        {
            set
            {
                _currentDirectory = value;
            }
        }

        public void MoveToThumbnail(ThumbnailBox thumbnail)
        {
            if (thumbnail != null)
            {
                SuspendLayout();

                SetThumbnailBorder(BorderStyle.None);
                _currentThumbnail = thumbnail;
                SetThumbnailBorder(BorderStyle.Fixed3D);
                ScrollControlIntoView(_currentThumbnail);

                ResumeLayout(true);
            }
        }

        public void MoveToNextThumbnail()
        {
            MoveToThumbnail(NextThumbnail);
        }

        public void MoveToPreviousThumbnail()
        {
            MoveToThumbnail(PreviousThumbnail);
        }

        public ThumbnailBox CurrentThumbnail
        {
            get { return _currentThumbnail; }
            set { _currentThumbnail = value; }
        }

        public ThumbnailBox NextThumbnail
        {
            get
            {
                if (_currentThumbnail == null)
                {
                    if (Controls.Count > 0)
                        return (ThumbnailBox)Controls[0];
                    else
                        return null;
                }
                else
                {
                    if (_currentThumbnail.ThumbnailIndex < Controls.Count - 1)
                        return (ThumbnailBox)Controls[_currentThumbnail.ThumbnailIndex + 1];
                    else
                        return null;
                }
            }
        }

        public ThumbnailBox PreviousThumbnail
        {
            get
            {
                if (_currentThumbnail == null)
                {
                    if (Controls.Count > 0)
                        return (ThumbnailBox)Controls[Controls.Count - 1];
                    else
                        return null;
                }
                else
                {
                    if (_currentThumbnail.ThumbnailIndex > 0)
                        return (ThumbnailBox)Controls[_currentThumbnail.ThumbnailIndex - 1];
                    else
                        return null;
                }
            }
        }

        public void StopThumbnailsGeneration()
        {
            if (_tasksDispatcher != null)
            {
                _tasksDispatcher.Stop();

                for (var i = 0; (i < 10) && (!_tasksDispatcher.IsStopped); i++)
                {
                    Thread.Sleep(50);
                    Application.DoEvents();
                }

                DisposeOfPreviousThumbnails();
            }
        }


        #region Private

        private delegate ThumbnailBox CreateThumbnailBoxDelegate(int i);

        private static readonly Point Point0 = new Point(0, 0);

        private string _currentDirectory;
        private IList<ImageFile> _imageFiles;

        private TasksDispatcher _tasksDispatcher;

        private ThumbnailBox _currentThumbnail;

        private bool _allowSetThumbnailBorder;
        private bool _pendingAction;

        private void GetImageFiles()
        {
            var imageFolder = new ImageFolder(_currentDirectory);
            _imageFiles = imageFolder.GetImageFiles();
        }

        private void SetThumbnailBorder(BorderStyle borderStyle)
        {
            if (_allowSetThumbnailBorder)
            {
                if (_currentThumbnail != null)
                {
                    _currentThumbnail.SetBorder(borderStyle);
                    _currentThumbnail.Select();
                }
            }
        }

        private void GenerateThumbnail(object index)
        {
            ThumbnailBox thumbnailBox;

            if (InvokeRequired)
                thumbnailBox = (ThumbnailBox)Invoke(
                    new CreateThumbnailBoxDelegate(GenerateThumbnailHelper), (int)index);
            else
                thumbnailBox = GenerateThumbnailHelper((int)index);

            thumbnailBox.ReadImageFromDiscThread();
        }

        private ThumbnailBox GenerateThumbnailHelper(int i)
        {
            var thumbnailBox = new ThumbnailBox(this, i, _imageFiles[i]);
            Controls.Add(thumbnailBox);

            if (_currentThumbnail == null)
                MoveToThumbnail(thumbnailBox);

            return thumbnailBox;
        }

        private void SetThumbnails()
        {
            _tasksDispatcher = new TasksDispatcher(GenerateThumbnail, SetThumbnailImage,
                                                   _imageFiles.Count);
            _tasksDispatcher.Start();
        }

        private void SetThumbnailImage(object index)
        {
            var aThumbnailBox = (ThumbnailBox)Controls[(int)index];
            aThumbnailBox.SetThumbnailImageThread();
        }

        #endregion


        #region Protected

        protected override void OnPaint(PaintEventArgs args)
        {
            base.OnPaint(args);

            if ((_pendingAction) && (_currentThumbnail != null))
            {
                ScrollControlIntoView(_currentThumbnail);
                _pendingAction = false;
            }
        }

        protected override void OnMouseMove(MouseEventArgs args)
        {
            base.OnMouseMove(args);

            if ((_currentThumbnail != null) && (!_currentThumbnail.Focused))
                _currentThumbnail.Focus();
        }

        #endregion
    }
}
